#pragma once

#include <list>

#include "mission.h"
#include "occupy_empty_mission.h"
#include "params.h"

class basic_setup_mission : public mission
{
public:
	std::list<Position> occupying_cities;

	basic_setup_mission(mission *parent_mission, const gtype_list &troop) : mission(parent_mission, troop) 
	{
		occupying_cities.clear();
	}

	bool city_assigned(Position p)
	{
		for (std::list<Position>::iterator it = occupying_cities.begin(); it != occupying_cities.end(); ++it)
			if (*it == p) 
				return true;
		return false;
	}

	bool find_target(GeneralType general, Position &target)
	{
		UserAPI &api = mission_manager::get_intance()->get_api();
		int min_dist = INFINITY;
		target = Position(-1, -1);
		Position start = api.get_my_army(general)->pos;
		for (int i = 0; i < api.all_cities.size(); i ++)
			if (api.all_cities[i]->owner == -1) {
				Position t = api.GetCityCenter(api.all_cities[i]);
				if (city_assigned(t)) continue;
				if (api.HamDistance(start, t) < min_dist) {
					min_dist = api.HamDistance(start, t);
					target = t;
				}
			}

		return (min_dist < INFINITY);
	}

	virtual void execute()
	{
		LOG << this->get_type() << " executing"  << endl;
		UserAPI &api = mission_manager::get_intance()->get_api();

		for (gtype_list::iterator it = m_troop.begin(); it != m_troop.end(); ++it)
		{
			Position target;

			if (find_target(*it, target)) 
			{
				gtype_list gl;
				gl.push_back(*it);
				occupy_empty_mission *oem = new occupy_empty_mission(this, gl, target);
				occupying_cities.push_back(target);
				set_army_state(*it, true);
				add_subtask(oem);
				oem->execute();
			}
		}
	}

	virtual void event_arrived(mission_event *e)
	{
		LOG << this->get_type() << " event_arrived"  << endl;
		UserAPI &api = mission_manager::get_intance()->get_api();
		if (e->get_type() == "occupy_completed_event")
		{
			occupy_empty_mission::occupy_completed_event *oce = (occupy_empty_mission::occupy_completed_event*)e;
			occupy_empty_mission *oem = (occupy_empty_mission*) oce->get_mission();
			remove_subtask(oem);
			assert(oem->m_troop.size() == 1);

			//	mark the city as a completed task
			for (std::list<Position>::iterator it = occupying_cities.begin(); it != occupying_cities.end(); )
			{
				if (*it == oem->m_target)
					it = occupying_cities.erase(it);
				else
					++it;
			}

			//	mark the city as a completed task
			for (gtype_list::iterator it = oem->m_troop.begin(); it != oem->m_troop.end(); ++it)
			{
				Position p;
				if (find_target(*it, p))
				{
					gtype_list gl;
					gl.push_back(*it);
					occupy_empty_mission *next_oem = new occupy_empty_mission(this, gl, p);
					set_army_state(*it, true);
					add_subtask(next_oem);
					next_oem->execute();
				} else
				{
					free_general(*it);
					set_army_state(*it, false);
				}
			}
			
			delete oem;	//	yet memory is not the bottleneck right now.

			return;
		}

		LOG << "unhandled event " << e->get_type();
		abort();
	}

	virtual void cancel()
	{
	}

	virtual std::string get_type() { return "basic_setup_mission"; };
};